﻿using System.Globalization;
using System.IO;

using HtmlAgilityPack;

namespace NCrawler.HtmlProcessor.Extensions
{
    public static class HtmlToText
	{
		public static string ExtractText(this HtmlDocument htmlDocument)
		{
			using (var sw = new StringWriter(CultureInfo.InvariantCulture))
			{
				ConvertTo(htmlDocument.DocumentNode, sw);
				sw.Flush();
				return sw.ToString();
			}
		}

		public static DocumentWithLinks GetLinks(this HtmlDocument htmlDocument)
		{
			return new DocumentWithLinks(htmlDocument);
		}

		private static void ConvertContentTo(HtmlNode node, TextWriter outText)
		{
			foreach (var subnode in node.ChildNodes)
			{
				ConvertTo(subnode, outText);
			}
		}

		private static void ConvertTo(HtmlNode node, TextWriter outText)
		{
			string html;
			switch (node.NodeType)
			{
				case HtmlNodeType.Comment:
					// don't output comments
					break;

				case HtmlNodeType.Document:
					ConvertContentTo(node, outText);
					break;

				case HtmlNodeType.Text:
					// script and style must not be output
					var parentName = node.ParentNode.Name;
					if ((parentName == "script") || (parentName == "style"))
						break;

					// get text
					html = ((HtmlTextNode) node).Text;

					// is it in fact a special closing node output as text?
					if (HtmlNode.IsOverlappedClosingElement(html))
						break;

					// check the text is meaningful and not a bunch of whitespaces
					if (html.Trim().Length > 0)
					{
						outText.Write(HtmlEntity.DeEntitize(html));
						outText.Write(" ");
					}
					break;

				case HtmlNodeType.Element:
					switch (node.Name)
					{
						case "p":
							// treat paragraphs as crlf
							outText.Write("\r\n");
							break;
					}

					if (node.HasChildNodes)
					{
						ConvertContentTo(node, outText);
					}
					break;
			}
		}
	}
}